import os
import sys
import time

from my_tool import Color, Bash, File, Git

POM_PATH = 'pom.xml'
# TODO idea 路径
IDEA_PATH = '/Users/jl/IdeaProjects'
# TODO 本地 Maven 库路径
MAVEN_PATH = '/Users/jl/.m2/repository/cn/{}/{}'
# 正式包名称
MVNREP = 'mvnrep'
# TODO 测试包名称
MVNREP2 = 'xxx'
# TODO 正式包路径
MVNREP_PATH = IDEA_PATH + '/' + MVNREP
# TODO 测试包路径
MVNREP2_PATH = IDEA_PATH + '/' + MVNREP2
# TODO mvnadmin.app_user.password
AUTHKEY = 'xxx'
VERSION = '1.0.0-SNAPSHOT'
JAR_FANTASYWORKS_PATH = '{}/{}/repository/cn/fantasyworks/{}/{}'.format(IDEA_PATH, '{}', '{}', VERSION)
JAR_FANCYLAB_PATH = '{}/{}/repository/cn/fancylab/{}/{}'.format(IDEA_PATH, '{}', '{}', VERSION)
FANCY_MODULE = 'src/main/resources/fancy-module.txt'
# TODO 跳过回退本地代码版本到正式包版本的包
JUMP_RESET_MODULES = ['sso', 'mall', '.DS_Store']
MAIN_BRANCHS = ['main', 'master']
MVN_CLEAN = 'mvn clean install -e -U -Dmaven.test.skip=true'
MVN_RESOLVE = 'mvn dependency:resolve'
# TODO 跳过无需切分支的模块
JUMP_BRANCH_MODULES = ['reserve-client', 'mall', 'theatre-merchant-client', 'theatre-sport', 'thvendor-client',
                       '.DS_Store', 'leaguer-dubbo-client', 'thvendor-travel']


def is_brief_param(param):
    """
    是否简写参数，-t 而不是 --test
    :param param:
    :return:
    """
    return param.startswith('-') and not param.startswith('--')


def jar_package():
    """
    打包
    :return:
    """
    if not File.file_exits(POM_PATH):
        Color.red(POM_PATH + ' not exists')
        sys.exit(0)
    if Bash.is_cmd_out("grep 'fancy-springboot' pom.xml"):
        Color.red('主程序不能打包')
        sys.exit(0)
    # 测试打包
    test = len(args) == 2
    # repo 打包
    repo = False
    # 正式打包
    formal = False
    # 测试正式一起打包
    test_and_formal = False
    # 是否强制打包，即使版本一致
    force = False
    # 推送
    push = False
    # maven 强制更新
    clean = False
    # 重新加载依赖
    resolve = False
    # 删除本地 jar 包
    delete = False
    # 打多个包
    module_names = []
    cur_module_name = Bash.get_run_cmd_result('basename $(pwd)').replace('\n', '')
    module_names.append(cur_module_name)
    for param in args[2:]:
        if param == 'mvn':
            break
        brief_param = is_brief_param(param)
        if param == '--test' or (brief_param and 't' in param):
            test = True
        if param == '--repo':
            repo = True
        if param == '--formal':
            formal = True
        if param == '--all' or (brief_param and 'a' in param):
            test_and_formal = True
        if param == '--force' or (brief_param and 'f' in param):
            force = True
        if param == '--push' or (brief_param and 'p' in param):
            push = True
        if param == '--clean' or (brief_param and 'c' in param):
            clean = True
        if param == '--resolve' or (brief_param and 'r' in param):
            resolve = True
        if param == '--delete' or (brief_param and 'd' in param):
            delete = True
        if param == '--specify':
            module_names = args[args.index('--specify') + 1:]
    if delete:
        delete_mvn_jar(args[3])
        sys.exit(0)
    if test:
        Bash.only_run_cmd('git -C {}/{} pull'.format(IDEA_PATH, MVNREP2))
    if formal:
        Bash.only_run_cmd('git -C {}/{} pull'.format(IDEA_PATH, MVNREP))
    if test_and_formal:
        Bash.only_run_cmd('git -C {}/{} pull'.format(IDEA_PATH, MVNREP2))
        Bash.only_run_cmd('git -C {}/{} pull'.format(IDEA_PATH, MVNREP))
    for module_name in module_names:
        module_name = Bash.get_run_cmd_result('basename ' + module_name).replace('\n', '')
        if module_name == cur_module_name:
            if clean:
                Bash.only_run_cmd(MVN_CLEAN)
                continue
            if resolve:
                Bash.only_run_cmd(MVN_RESOLVE)
                continue
            Color.yellow(cur_module_name)
            Bash.only_run_cmd('git pull')
            # 获取当前版本
            commit = Git.get_commit('.')
            Color.green('commit ' + commit)
            pack(test, repo, formal, test_and_formal, commit, module_name, force)
        else:
            os.chdir(Bash.get_run_cmd_result('pwd').replace('\n', '').replace(cur_module_name, module_name))
            if clean:
                Bash.only_run_cmd(MVN_CLEAN)
                continue
            if resolve:
                Bash.only_run_cmd(MVN_RESOLVE)
                continue
            cur_module_name = Bash.get_run_cmd_result('basename $(pwd)').replace('\n', '')
            Color.yellow(cur_module_name)
            Bash.only_run_cmd('git pull')
            # 获取当前版本
            commit = Git.get_commit('.')
            Color.green('commit ' + commit)
            pack(test, repo, formal, test_and_formal, commit, module_name, force)
    if push:
        jar_package_push(test, repo, formal, test_and_formal, module_names)


def pack(test, repo, formal, test_and_formal, commit, module_name, force):
    if test:
        test_package(repo, commit, module_name, force)
    elif formal:
        formal_package(commit, module_name)
    elif test_and_formal:
        test_package(repo, commit, module_name, force)
        formal_package(commit, module_name)
    else:
        Color.red('打包参数有误')
        sys.exit(0)
    jar_package_finish()


def mvn_module(module_name, package_name):
    """
    打包
    :param module_name:
    :param package_name:
    :return:
    """
    Color.green('开始打包')
    if not File.file_exits(FANCY_MODULE):
        Bash.only_run_cmd('mkdir -p src/main/resources/')
        Bash.only_run_cmd('echo {} >{}'.format(module_name, FANCY_MODULE))
        Bash.only_run_cmd('git log -1 >>{}'.format(FANCY_MODULE))
        Bash.only_run_cmd('mvn -q clean:clean')
    Bash.only_run_cmd('rm -fr {}/{}/repository/cn/fancylab/{}'.format(IDEA_PATH, package_name, module_name))
    Bash.only_run_cmd('rm -fr {}/{}/repository/cn/fantasyworks/{}'.format(IDEA_PATH, package_name, module_name))
    Bash.only_run_cmd(
        'mvn -q -Dmaven.test.skip=true deploy -DaltDeploymentRepository=fancy-lab::default::file:{}/{}/repository/'
        .format(IDEA_PATH, package_name))


def get_jar_commit(package_name, module_name):
    """
    获取 jar 包版本
    :param package_name:
    :param module_name:
    :return:
    """
    jar_commit_cmd = "cat fancy-module.txt | grep ^commit | awk -F ' ' '{print $2}'"
    jar_commit = ''
    if File.file_exits(JAR_FANTASYWORKS_PATH.format(package_name, module_name)):
        Bash.only_run_cmd(
            'jar -xf {}/{}/repository/cn/fantasyworks/{}/{}/{}-*-1.jar fancy-module.txt'.format(IDEA_PATH, package_name,
                                                                                                module_name, VERSION,
                                                                                                module_name))
        jar_commit = Bash.get_run_cmd_result(jar_commit_cmd)
        Bash.only_run_cmd('rm fancy-module.txt')
    elif File.file_exits(JAR_FANCYLAB_PATH.format(package_name, module_name)):
        Bash.only_run_cmd(
            'jar -xf {}/{}/repository/cn/fancylab/{}/{}/{}-*-1.jar fancy-module.txt'.format(IDEA_PATH, package_name,
                                                                                            module_name, VERSION,
                                                                                            module_name))
        jar_commit = Bash.get_run_cmd_result(jar_commit_cmd)
        Bash.only_run_cmd('rm fancy-module.txt')
    else:
        Color.red('jar 包不存在')
    return jar_commit


def delete_mvn_jar(module_name):
    """
    删除本地 jar 包
    :param module_name:
    :return:
    """
    fantasyworks_path = MAVEN_PATH.format('fantasyworks', module_name)
    fancylab_path = MAVEN_PATH.format('fancylab', module_name)
    if File.file_exits(fantasyworks_path):
        Bash.only_run_cmd('rm -rf ' + fantasyworks_path, True)
    elif File.file_exits(fancylab_path):
        Bash.only_run_cmd('rm -rf ' + fancylab_path, True)
    else:
        Color.red('jar 包不存在')


def test_package(repo, commit, module_name, force):
    Color.green('测试打包')
    time.sleep(1)
    package_names = [MVNREP2]
    if repo:
        package_names.append('repo')
    for package_name in package_names:
        Bash.only_run_cmd('git -C {}/{} pull'.format(IDEA_PATH, package_name))
        jar_commit = get_jar_commit(package_name, module_name)
        Color.green('{} {} jar_commit {}'.format(package_name, module_name, jar_commit))
        if commit == jar_commit and not force:
            Color.green('测试版本一致，跳过')
            return
        mvn_module(module_name, package_name)


def formal_package(commit, module_name):
    Color.green('正式打包')
    time.sleep(1)
    branch = Git.get_branch('.')
    if branch not in MAIN_BRANCHS:
        Color.red('不在主干分支: {} {}'.format(module_name, branch))
        sys.exit(0)
    package_name = MVNREP
    Bash.only_run_cmd('git -C {}/{} pull'.format(IDEA_PATH, package_name))
    jar_commit = get_jar_commit(package_name, module_name)
    Color.green('{} {} jar_commit {}'.format(package_name, module_name, jar_commit))
    if commit == jar_commit:
        Color.green('正式版本一致，跳过')
        return
    mvn_module(module_name, package_name)


def jar_package_finish():
    if File.file_exits(FANCY_MODULE):
        Bash.only_run_cmd('rm {}'.format(FANCY_MODULE))
        Color.green('打包完成')


def jar_package_push(test, repo, formal, test_and_formal, module_names: list):
    program_path = Bash.get_run_cmd_result('pwd').replace('\n', '')
    Color.green('当前目录：' + program_path)
    if test:
        test_push(repo, module_names)
    elif formal:
        formal_push()
    elif test_and_formal:
        test_push(repo, module_names)
        formal_push()
    else:
        raise Exception('提交参数有误')
    Color.green('提交更新完成')
    os.chdir(program_path)


def test_push(repo, module_names: list):
    """
    测试提交推送
    :return:
    """
    if not module_names or len(module_names) == 0:
        raise Exception('推送 module 不存在')
    Color.green('测试提交')
    time.sleep(1)
    push_paths = [MVNREP2_PATH]
    if repo:
        push_paths.append(IDEA_PATH + '/repo')
    for push_path in push_paths:
        os.chdir(push_path)
        Bash.only_run_cmd('git pull')
        nothing_commit = Bash.get_run_cmd_result('git status | grep "nothing to commit"')
        if nothing_commit:
            Color.green("=== 测试当前没有新增或者修改的文件 ===")
            return
        Bash.only_run_cmd('git add . && git commit -m upgrade && git push')
        for module_name in module_names:
            module_name = Bash.get_run_cmd_result('basename ' + module_name).replace('\n', '')
            Bash.only_run_cmd(
                'curl "https://antadmin.lengliwh.com/mvnadmin/publish/push.xhtml?authKey={}&moduleName={}"'.format(
                    AUTHKEY, module_name), True)


def formal_push():
    """
    正式提交推送
    :return:
    """
    Color.green('正式提交并更新 jar 包')
    time.sleep(1)
    os.chdir(MVNREP_PATH)
    Bash.only_run_cmd('git pull')
    nothing_commit = Bash.get_run_cmd_result('git status | grep "nothing to commit"')
    if nothing_commit:
        Color.green("=== 正式当前没有新增或者修改的文件 ===")
        return
    Bash.only_run_cmd('git add . && git commit -m upgrade && git push')
    Color.green('正式更新 jar 包')
    time.sleep(1)
    Bash.only_run_cmd('ssh root@devserver1 \'su maven -c "git -C /opt/mvnrep/mvnrep1/ pull"\'')


def reset_formal(path):
    """
    回退本地代码版本到正式包版本，便于 review 代码
    :return:
    """
    if path is None:
        Color.red('路径不存在')
        sys.exit(0)
    Bash.only_run_cmd('git -C {} pull'.format(MVNREP_PATH))
    files = File.path_files(path)
    hard = False
    for param in args[2:]:
        if param == 'reset_formal':
            break
        if param == '--specify':
            files = args[args.index('--specify') + 1:]
        if param == '--hard':
            hard = True
    reset_paths = []
    formal_commit = {}
    formal_not_exist_modules = []
    for filepath in files:
        module_name = Bash.get_run_cmd_result('basename ' + filepath).replace('\n', '')
        if module_name in JUMP_RESET_MODULES:
            continue
        branch = Git.get_branch(filepath)
        if branch not in MAIN_BRANCHS:
            Color.red('不在主干分支: {} {}'.format(module_name, branch))
            sys.exit(0)
        nothing_commit = Bash.get_run_cmd_result('git -C {} status | grep "nothing to commit"'.format(filepath))
        if not nothing_commit:
            Color.yellow('{} 模块有未提交的代码'.format(module_name))
            return
        Bash.only_run_cmd('git -C {} pull'.format(filepath))
        formal_jar_commit = get_jar_commit(MVNREP, module_name)
        if not formal_jar_commit:
            formal_not_exist_modules.append(module_name)
        else:
            Color.green('{} {}'.format(module_name, formal_jar_commit))
        commit = Git.get_commit(filepath)
        if commit == formal_jar_commit:
            continue
        reset_paths.append(filepath)
        formal_commit[module_name] = formal_jar_commit
    if len(formal_not_exist_modules) > 0:
        Color.red('正式包版本不存在的模块: {}'.format(formal_not_exist_modules))
    Color.green('有变更的模块: {}'.format(list(formal_commit.keys())))
    for reset_path in reset_paths:
        module_name = Bash.get_run_cmd_result('basename ' + reset_path).replace('\n', '')
        formal_jar_commit = formal_commit[module_name]
        if hard:
            Bash.only_run_cmd('git -C {} reset --hard {}'.format(reset_path, formal_jar_commit))
        else:
            Bash.only_run_cmd('git -C {} reset {}'.format(reset_path, formal_jar_commit))


def git_tool(path):
    """
    查询/检出指定路径下的所有包到指定分支
    :param path:
    :return:
    """
    if path is None:
        Color.red('路径不存在')
        sys.exit(0)
    checkout = False
    fetch = False
    pull = False
    check_branchs = None
    delete_branch = False
    force_delete_branch = False
    delete_branch_names = None
    files = File.path_files(path)
    not_commit_modules = []
    for idx, param in enumerate(args[2:]):
        if param == 'git':
            break
        brief_param = is_brief_param(param)
        if param == '--branch_name' or (brief_param and 'b' in param):
            check_branchs = args[idx + 2 + 1]
        if param == '--checkout' or (brief_param and 'c' in param):
            checkout = True
        if param == '--fetch' or (brief_param and 'f' in param):
            fetch = True
        if param == '--pull' or (brief_param and 'p' in param):
            pull = True
        if param == '--delete' or (brief_param and 'd' in param):
            delete_branch = True
            delete_branch_names = args[idx + 2 + 1]
        if brief_param and 'D' in param:
            force_delete_branch = True
            delete_branch_names = args[idx + 2 + 1]
        if param == '--specify':
            files = args[idx + 1:]
    if checkout and check_branchs is None:
        Color.red('检出分支不存在')
        sys.exit(0)
    for filepath in files:
        if os.path.isfile(filepath):
            continue
        if not Git.is_git(filepath):
            continue
        if fetch:
            Bash.only_run_cmd('git -C {} fetch -p'.format(filepath), True)
        if pull:
            Bash.only_run_cmd('git -C {} pull'.format(filepath), True)
        local_branch = Git.get_branch(filepath)
        if checkout or check_branchs is not None:
            module_name = Bash.get_run_cmd_result('basename ' + filepath).replace('\n', '')
            if module_name in JUMP_BRANCH_MODULES:
                Color.yellow('跳过 {}'.format(module_name))
                continue
            nothing_commit = Bash.get_run_cmd_result('git -C {} status | grep "nothing to commit"'.format(filepath))
            if not nothing_commit:
                Color.yellow('{} 模块有未提交的代码'.format(module_name))
                not_commit_modules.append(module_name)
                continue
            for check_branch in check_branchs.split(','):
                have_branch = Bash.get_run_cmd_result(
                    'git -C {} branch -a | grep -E "^\\s*{}$|/{}$"'.format(filepath, check_branch, check_branch), False,
                    True)
                if have_branch:
                    if checkout:
                        if local_branch == check_branch:
                            break
                        else:
                            Bash.only_run_cmd('git -C {} checkout {}'.format(filepath, check_branch), True)
                            if pull:
                                Bash.only_run_cmd('git -C {} pull'.format(filepath), True)
                            break
                    else:
                        Color.green(module_name)
        if (delete_branch or force_delete_branch) and delete_branch_names is not None:
            module_name = Bash.get_run_cmd_result('basename ' + filepath).replace('\n', '')
            if module_name in JUMP_BRANCH_MODULES:
                Color.yellow('跳过 {}'.format(module_name))
                continue
            nothing_commit = Bash.get_run_cmd_result('git -C {} status | grep "nothing to commit"'.format(filepath))
            if not nothing_commit:
                Color.yellow('{} 模块有未提交的代码'.format(module_name))
                not_commit_modules.append(module_name)
                continue
            for delete_branch_name in delete_branch_names.split(','):
                l_branch = Bash.get_run_cmd_result(
                    'git -C {} branch -a | grep -E "^\\s*{}$"'.format(filepath, delete_branch_name, delete_branch_name),
                    False, True)
                r_branch = Bash.get_run_cmd_result(
                    'git -C {} branch -a | grep -E "/{}$"'.format(filepath, delete_branch_name, delete_branch_name),
                    False, True)
                if l_branch or r_branch:
                    if local_branch == delete_branch_name:
                        Color.yellow('{} 模块在待删除分支'.format(module_name))
                        break
                    else:
                        delete_branch_confirm = input(
                            Color.yellow("请确认是否删除 {} 的 {} 分支 y/n: ".format(module_name, delete_branch_name),
                                         False))
                        if delete_branch_confirm == 'y':
                            if l_branch:
                                delete = 'd'
                                if force_delete_branch:
                                    delete = 'D'
                                Bash.only_run_cmd(
                                    'git -C {} branch -{} {}'.format(filepath, delete, delete_branch_name), True)
                            if r_branch:
                                Bash.only_run_cmd(
                                    'git -C {} push origin --delete {}'.format(filepath, delete_branch_name), True)
    if len(not_commit_modules) > 0:
        Color.red('有未提交代码的模块: {}'.format(not_commit_modules))


def tool_help():
    print(
        'ptool (mvn | git)'
        'mvn 打包工具'
        'git 分支工具'
    )


def mvn_help():
    print(
        'ptool mvn [-h | --help] [-t | --test] [--repo] [--formal] [-a | --all] [-f | --force] [-p | --push] [-c | --clean] [-r | --resolve] [-d | --delete] [--specify]\n'
        '\n'
        '-t, --test     测试打包/推送\n'
        '--repo         测试 repo 打包/推送\n'
        '--formal       正式打包/推送\n'
        '-a, --all      测试、正式一块儿打包/推送\n'
        '-f, --force    无视版本差异强制打包\n'
        '-p, --push     推送\n'
        '-c, --clean    maven 将打包好的 jar 或 war 文件安装到本地仓库中，以便其他项目可以引用\n'
        '-r, --resolve  重新加载依赖\n'
        '-d, --delete   删除本地 jar 包，后面直接跟 jar 包名\n'
        '--specify      指定路径打包，如 ../a ../b ../c'
    )


def git_help():
    print(
        'ptool git [-h | --help] (path) [(-b | --branch_name) -c | --checkout] [-f | --fetch] [-p | --pull] [(-c | --checkout) --specify]\n'
        '\n'
        'path               指定待操作的 git 仓库上层路径\n'
        '-b, --branch_name  查看或检出的分支名称，支持多个分支，如 a,b,c\n'
        '-c, --checkout     和 -b 一块儿使用检出 -b 指定的多个分支，多个分支只检出匹配的第一个\n'
        '-f, --fetch        刷新分支\n'
        '-p, --pull         拉取代码\n'
        '-d, --delete       删除本地/远程分支，D强制删除\n'
        '-D                 强制删除本地/远程分支，D强制删除\n'
        '--specify          指定路径切换分支，与 -c 或 --checkout 配合使用'
    )


def reset_formal_help():
    print(
        'ptool reset_formal (path) [--hard] [--specify]\n'
        '\n'
        'path       需要回退到正式版本的仓库路径\n'
        '--hard     硬回退到线上分支\n'
        '--specify  指定具体回退到正式版本的模块'
    )


if __name__ == '__main__':
    """
    将如下命令（视自己情况微调命令）放入 ~/.zshrc 文件中，然后 source ~/.zshrc 即可
    source /Users/jl/PycharmProjects/python-tool/complete.sh
    alias ptool='python3 /Users/jl/PycharmProjects/python-tool/ptool.py'
    """
    args = sys.argv
    try:
        if args[1] == '-h' or args[1] == '--help':
            tool_help()
        elif args[1] == 'mvn':
            if len(args) > 2 and (args[2] == '-h' or args[2] == '--help'):
                mvn_help()
            else:
                jar_package()
        elif args[1] == 'git':
            if len(args) > 2 and (args[2] == '-h' or args[2] == '--help'):
                git_help()
            else:
                git_tool(args[2])
        elif args[1] == 'reset_formal':
            if len(args) > 2 and (args[2] == '-h' or args[2] == '--help'):
                reset_formal_help()
            else:
                reset_formal(args[2])
        else:
            Color.red('参数有误')
    except BaseException as e:
        Color.red(e)
        sys.exit(0)
